package edu.ccut.saturn.component.impl.directory;

import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import edu.ccut.saturn.component.IFileResourceInfo;
import edu.ccut.saturn.component.ILogger;
import edu.ccut.saturn.component.IResourceInfo;
import edu.ccut.saturn.component.SaturnComponentException;
import edu.ccut.saturn.component.SaturnLoggerManager;

/**
 * 根据属性文件生成<code>IResourceInfo</code>类型实例的单态工厂类。
 * 属性文件中记录了文件资源的类型及对应的实现类。如果增加或减少了现有的文件资源的类型需要相应的改变属性文件的内容。
 * 
 * @author 温建
 * 
 * @version 1.0 2008.8.29
 * 
 */
public class SaturnResourceFactory {

	protected static ILogger logger = SaturnLoggerManager.getInstance()
			.getSaturnLogger(SaturnLoggerManager.LOGGER_KEY_LOAD_BUNDLE);

	private static final String CONFIG_FILE_NAME = "config_file.properties";

	private static SaturnResourceFactory instance;

	static {
		instance = new SaturnResourceFactory();
	}

	private Map<String, Class<?>> configClassMap;

	private SaturnResourceFactory() {
		loadDirectoryClass();
	}

	/**
	 * 获得<code>SaturnResourceFactory</code>的单态实例
	 * 
	 * @return
	 */
	public static SaturnResourceFactory getInstance() {
		return instance;
	}

	/**
	 * 创建文件资源实例的方法。根据传入的参数type判断要创建哪种类型的文件资源实例。
	 * 
	 * @param directoryPath
	 *            待创建的文件资源实例的所在路径信息
	 * @param fileName
	 *            待创建的文件资源实例记录的文件名称
	 * @return
	 * @throws SaturnComponentException
	 */
	public IResourceInfo createFileResource(String directoryPath,
			String fileName) throws SaturnComponentException {

		try {

			if (this.configClassMap.containsKey(fileName)) {
				Class<?> configClass = this.configClassMap.get(fileName);
				IFileResourceInfo resourceInfo = (IFileResourceInfo) configClass
						.newInstance();

				resourceInfo.setDirectoryPath(directoryPath);
				return resourceInfo;
			}

		} catch (InstantiationException e) {
			e.printStackTrace();

		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		throw new SaturnComponentException("the config file resource : "
				+ fileName + " is not valid");
	}

	@SuppressWarnings("unchecked")
	private void loadDirectoryClass() {
		Properties properties = new Properties();
		InputStream in = null;
		this.configClassMap = new HashMap<String, Class<?>>();

		try {
			in = SaturnResourceFactory.class
					.getResourceAsStream(CONFIG_FILE_NAME);

			if (in == null) {
				logger
						.warn("can't find edu/ccut/saturn/component/impl/directoryLoad/config_file.properties, load resourse defaultly.");

				this.configClassMap.put("menu.config",
						MenuConfigFileResourceInfo.class);
				this.configClassMap.put("authority.config",
						AuthorityConfigFileResourceInfo.class);
				this.configClassMap.put("database.config",
						DatabaseConfigFileResourceInfo.class);
				this.configClassMap.put("filter.config",
						FilterConfigFileResourceInfo.class);
			} else {
				properties.load(in);
				for (Enumeration propertyNames = properties.propertyNames(); propertyNames
						.hasMoreElements();) {

					String key = (String) propertyNames.nextElement();
					String className = properties.getProperty(key);

					try {
						this.configClassMap.put(key, Class.forName(className));
					} catch (ClassNotFoundException e) {
						logger.debug(
								"SaturnResourceFactory initialization error! Can not create instance of class ["
										+ className + "]", e);
					}
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (in != null) {
				try {
					in.close();
				} catch (IOException e) {
					logger.error("can not close the input stream of file"
							+ CONFIG_FILE_NAME, e);
				}
			}
		}
	}
}
